<template>
  <!-- 核销对话框 -->
  <Dialog v-model="dialogVisible" title="订单核销" width="35%">
    <el-form
      ref="formRef"
      v-loading="formLoading"
      :model="formData"
      :rules="formRules"
      label-width="100px"
    >
      <el-form-item v-if="supportSerial" prop="serialPort" label="扫描枪">
        <el-button
          type="primary"
          @click="connectToSerialPort"
          :disabled="serialPort"
          v-hasRole="['shop_admin', 'shop_staff']"
        >
          连接
        </el-button>
        <el-button
          type="danger"
          @click="cutPort"
          :disabled="!serialPort"
          v-hasRole="['shop_admin', 'shop_staff']"
        >
          断开
        </el-button>
      </el-form-item>
      <el-form-item prop="verifyCode" label="核销码">
        <el-input v-model="formData.verifyCode" placeholder="请输入核销码" />
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button type="primary" :disabled="formLoading" @click="getOrderByVerifyCodeClick">
        查询订单
      </el-button>
      <el-button @click="dialogVisible = false">取 消</el-button>
    </template>
  </Dialog>
  <!-- 核销确认对话框 -->
  <el-drawer v-model="detailDialogVisible" title="订单详情" width="55%" direction="rtl">
    <TradeOrderDetail v-if="orderDetails.id" :id="orderDetails.id" :show-pick-up="false" />
    <template #footer>
      <el-button type="primary" :disabled="formLoading" @click="submitForm"> 确认核销 </el-button>
      <el-button @click="detailDialogVisible = false">取 消</el-button>
    </template>
  </el-drawer>
</template>
<script lang="ts" setup>
import * as TradeOrderApi from '@/api/mall/trade/order'
import { OrderVO } from '@/api/mall/trade/order'
import { TradeOrderStatusEnum } from '@/utils/constants'
import TradeOrderDetail from '@/views/mall/trade/order/detail/index.vue'

/** 订单核销表单 */
defineOptions({ name: 'OrderVerifyForm' })

const message = useMessage() // 消息弹窗

const dialogVisible = ref(false) // 弹窗的是否展示
const detailDialogVisible = ref(false) // 详情弹窗的是否展示
const formLoading = ref(false) // 表单的加载中：1）修改时的数据加载；2）提交的按钮禁用
const formRules = reactive({
  verifyCode: [{ required: true, message: '核销码不能为空', trigger: 'blur' }]
})
const formData = ref<any>({
  verifyCode: '' // 核销码
})
const formRef = ref() // 表单 Ref
const orderDetails = ref<OrderVO>({})

/** 打开弹窗 */
const open = async (verifyCode: string = '') => {
  console.table(navigator?.serial)
  resetForm()
  if (verifyCode) {
    formData.value.verifyCode = verifyCode
    await getOrderByVerifyCode()
  } else {
    dialogVisible.value = true
  }
}
defineExpose({ open }) // 提供 open 方法，用于打开弹窗

/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件，用于操作成功后的回调
const submitForm = async () => {
  // 提交请求
  formLoading.value = true
  try {
    await TradeOrderApi.verifyOrderByVerifyCode(formData.value.verifyCode)
    message.success('核销成功')
    detailDialogVisible.value = false
    dialogVisible.value = false
    // 发送操作成功的事件
    emit('success', true)
  } finally {
    formLoading.value = false
  }
}

/** 重置表单 */
const resetForm = () => {
  formData.value = {
    verifyCode: '' // 核销码
  }
  formRef.value?.resetFields()
}

const getOrderByVerifyCodeClick = async () => {
  // 校验表单
  if (!formRef) return
  const valid = await formRef.value.validate()
  if (!valid) return
  await getOrderByVerifyCode()
}

/** 查询核销码对应的订单 */
const getOrderByVerifyCode = async () => {
  try {
    formLoading.value = true
    const data = await TradeOrderApi.getOrderByVerifyCode(formData.value.verifyCode)
    if (!data?.verifyCode) {
      message.error('未查询到订单')
      return
    }
    if (data?.status !== TradeOrderStatusEnum.UNDELIVERED.status) {
      message.error('订单不是待核销状态')
      return
    }
    orderDetails.value = data
    // 显示详情对话框
    detailDialogVisible.value = true
  } finally {
    formLoading.value = false
  }
}

const supportSerial = computed(() => {
  // 已知 Google Chrome 136.0.7103.48 不支持，Microsoft Edge 136.0.3240.50 支持
  return (
    'serial' in navigator &&
    navigator.serial != null &&
    typeof navigator.serial === 'object' &&
    'requestPort' in navigator.serial
  )
})

const port = ref('')
const ports = ref([])
const reader = ref('')
const serialPort = ref(false) // 是否连接扫码枪
/** 连接扫码枪 */
const connectToSerialPort = async () => {
  try {
    // 判断浏览器是否支持串口通信
    if (supportSerial.value) {
      // @ts-expect-error 提示用户选择一个串口
      port.value = await navigator.serial.requestPort()
    } else {
      message.error('当前浏览器不支持扫码枪，请更换浏览器（如 Microsoft Edge）再试')
      return
    }
    // @ts-expect-error 获取用户之前授予该网站访问权限的所有串口。
    ports.value = await navigator.serial.getPorts()
    // console.log(port.value, ports.value);
    // console.log(port.value)
    // @ts-expect-error 等待串口打开
    await port.value.open({ baudRate: 9600, dataBits: 8, stopBits: 2 })
    // console.log(typeof port.value);
    message.success('成功连接扫码枪')
    serialPort.value = true
    // readData(port.value);
    readData()
  } catch (error) {
    // 处理连接串口出错的情况
    console.log('Error connecting to serial port:', JSON.stringify(error))
    message.error('扫码枪连接失败')
  }
}
/** 监听扫码枪输入 */
const readData = async () => {
  // @ts-expect-error
  reader.value = port.value.readable.getReader()
  let data = '' //扫码数据
  // 监听来自串口的数据
  while (true) {
    // @ts-expect-error
    const { value, done } = await reader.value.read()
    if (done) {
      // @ts-expect-error 允许稍后关闭串口
      reader.value.releaseLock()
      break
    }
    // 获取发送的数据
    const serialData = new TextDecoder().decode(value)
    data = `${data}${serialData}`
    if (serialData.includes('\r')) {
      //读取结束
      let codeData = data.replace('\r', '')
      data = '' //清空下次读取不会叠加
      console.log(`二维码数据:${codeData}`)
      //处理拿到数据逻辑
      open(codeData)
    }
  }
}
/** 断开扫码枪 */
const cutPort = async () => {
  if (port.value !== '') {
    // @ts-expect-error
    await reader.value.cancel()
    // @ts-expect-error
    await port.value.close()
    port.value = ''
    message.success('已成功断开扫码枪连接')
    serialPort.value = false
  } else {
    message.warning('请先连接或打开扫码枪')
  }
}
</script>
